// 默认图标
const defaultIconName = 'arrow'
// 默认移动速度, 基于速度计算分段拆分个数
const defaultSpeed = 10
// 基于队列
const MovingMarker = L.Marker.extend({
    // 每一次移动都保存当前坐标, 暂停后仍可以继续
    currentLatLng: [],
    // 上一次旋转角度
    lastRotation: 0,
    // 构造函数, 主要是初始化各种数据
    initialize(startLatLng, options = {}) {
        this.startLatLng = L.latLng(startLatLng)
        this.nextDestination = this.startLatLng
        this.isZooming = false
        this.isPaused = false
        this.defaultDuration = 1000

        // 速度
        this.speed = options.speed || defaultSpeed
        // 处理图标
        const iconName = options.iconName || defaultIconName
        const icon = new RotatingIcon(iconName)

        this.setIcon(icon)
        this.icon = icon
        // call parent constructor
        L.Marker.prototype.initialize.call(this, startLatLng, options)
        this.fire('destination', startLatLng)

        // 基于队列, 队空后抛出destinationsdrained hook
        if (!options.coors || !options.coors) {
            return this.fire('destinationsdrained')
        }
        // destinations标识每一段所需的时间
        // 还可以在坐标点保存相关信息(待完善, 可在坐标点保存周边建筑的名称, 根据名称在featuregroup中查找对应图层并打开popup)
        this.destinations = this.processDestinations(options.coors)
    },
    /**
     * 根据速度, 计算每一段位移所需时间, 返回定长坐标点
     * @param {*} destinations
     * @param {*} unit 单位长度
     * @returns
     */
    processDestinations(destinations, unit) {
        if (!Array.isArray(destinations) || destinations.length < 2) {
            throw new Error('至少传两组坐标点')
        }
        const arr = []
        for (let i = 0; i < destinations.length - 1; i++) {
            const pre = destinations[i]
            const next = destinations[i + 1]
            const start = turf.point([pre[1], pre[0]])
            const end = turf.point([next[1], next[0]])
            // miles是英尺, 需要转换为米
            const distance = parseInt(turf.distance(start, end, { units: 'miles' }) * 1609.344)
            const duration = (distance / this.speed) * 1000
            arr.push({
                latLng: next,
                duration: duration,
                distance: distance
            })
        }
        return arr
    },
    onAdd(map) {
        // call origin onAdd
        L.Marker.prototype.onAdd.call(this, map)
        // call this
        this.start()
        this.map = map
        map.addEventListener('zoomstart', () => {
            this.isZooming = true
        })
        map.addEventListener('zoomend', () => {
            this.isZooming = false
        })
    },

    step() {
        const nextDestination = this.destinations.shift()
        // 计算方位角
        const start = turf.point([this.startLatLng.lng, this.startLatLng.lat])
        const end = turf.point([nextDestination.latLng[1], nextDestination.latLng[0]])
        let bearing = turf.bearing(start, end)
        // 需要翻转禁止动画
        const reverse = this.lastRotation !== 0 && Math.abs(this.lastRotation - bearing) >= 180
        nextDestination.rotation = bearing
        this.icon.rotate.call(this.icon, nextDestination.rotation, reverse)
        this.lastRotation = bearing

        this.fire('destination', nextDestination)

        this.nextLatLng = L.latLng(nextDestination.latLng)
        this.duration = nextDestination.duration || this.defaultDuration
    },
    start() {
        this.step()
        // 开始时间, 用来判断当前step是否结束
        this.startedAt = Date.now()
        this.isPaused = false
        // throw hook start
        this.fire('start')
        this.requestAnimationFrameSetLatLng()
    },
    pause() {
        this.fire('paused')
        this.isPaused = true
    },
    continue() {
        this.fire('continue')
        // 重置起点
        this.startLatLng = this.currentLatLng
        const coors = this.destinations.map(item => item.latLng)
        coors.unshift([this.nextLatLng.lat, this.nextLatLng.lng])
        coors.unshift([this.currentLatLng.lat, this.currentLatLng.lng])
        this.destinations.splice(0, this.destinations.length, ...this.processDestinations(coors))
        this.start()
    },
    requestAnimationFrameSetLatLng() {
        if (!this.isPaused) {
            requestAnimationFrame(this.setCurrentLatLng.bind(this))
        }
    },
    // 调整位置
    setCurrentLatLng() {
        const now = Date.now()
        const end = this.startedAt + this.duration

        // Schedule the next tick
        if (now < end) {
            this.requestAnimationFrameSetLatLng()
        } else {
            if (this.destinations.length) {
                // step to next destination
                this.startedAt = Date.now()
                this.startLatLng = this.nextLatLng
                this.step()
                this.requestAnimationFrameSetLatLng()
            } else {
                this.setLatLng(this.nextLatLng)
                return this.fire('destinationsdrained')
            }
        }

        if (!this.isZooming) {
            const t = now - this.startedAt
            // (this.nextLatLng.lat - this.startLatLng.lat) / duration = 速度
            // 速度 * 时间 = duration时间段内移动的距离
            // 移动的距离 + 初始位置 = 终点位置(当前时间点的位置)
            const lat =
                this.startLatLng.lat +
                ((this.nextLatLng.lat - this.startLatLng.lat) / this.duration) * t
            // lat和lng两个位置同时更新,确定最终坐标
            const lng =
                this.startLatLng.lng +
                ((this.nextLatLng.lng - this.startLatLng.lng) / this.duration) * t
            this.currentLatLng = L.latLng({ lat, lng })
            this.setLatLng({ lat, lng })
            // 通过project将地理坐标转为x,y像素点
            /*
                猜测: 
                1. 通过获取getBounds()可以获取到当前屏幕四个角的坐标,
                   左上和右上的经度作差得到经度的跨度,
                2. 通过getClientWidth()得到屏幕宽度
                3. 二者作差得到像素点和经纬度的比例关系
                4. 如果把左上角作为坐标原点, 根据目标点(121, 37)和原点的差值, 经过刚才得到比例运算, 大概可以得到屏幕上的像素坐标点
             */
            const rawPoint = this.map.project({ lat, lng })
            const point = rawPoint._subtract(this.map.getPixelOrigin())
            L.DomUtil.setPosition(this.getElement(), point)
            this.map.setView({ lat, lng }, this.map.getZoom(), { animate: false })
        }
        return
    }
})

L.marker.movingMarker = function (startLatLng, options = {}) {
    return new MovingMarker(startLatLng, options)
}

const iconBase64Map = {
    arrow: `
    <svg width="88px" height="88px" viewBox="0 0 88 88" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <defs>
        <path d="M39.9355054,1.13490366 C32.870916,16.0713222 7.02434876,70.7233431 0.194087297,85.1682687 L0.194087297,85.1682687 C-0.498967289,86.6367899 0.766999183,88.2661632 2.36162048,87.9633241 L2.36162048,87.9633241 L41.7078585,80.4797247 L81.081898,87.94148 C82.6765193,88.2433261 83.9405,86.6089882 83.2454596,85.14146 L83.2454596,85.14146 L43.5229069,1.1378824 C43.1644646,0.379295434 42.4455942,0 41.7267238,0 L41.7267238,0 C41.0088464,-0.00099096544 40.2929547,0.377309604 39.9355054,1.13490366" id="path-1"></path>
        <path d="M39.9355054,1.13490366 C32.870916,16.0713222 7.02434876,70.7233431 0.194087297,85.1682687 L0.194087297,85.1682687 C-0.498967289,86.6367899 0.766999183,88.2661632 2.36162048,87.9633241 L2.36162048,87.9633241 L41.7078585,80.4797247 L81.081898,87.94148 C82.6765193,88.2433261 83.9405,86.6089882 83.2454596,85.14146 L83.2454596,85.14146 L43.5229069,1.1378824 C43.1644646,0.379295434 42.4455942,0 41.7267238,0 L41.7267238,0 C41.0088464,-0.00099096544 40.2929547,0.377309604 39.9355054,1.13490366" id="path-3"></path>
        <path d="M39.9355054,1.13490366 C32.870916,16.0713222 7.02434876,70.7233431 0.194087297,85.1682687 L0.194087297,85.1682687 C-0.498967289,86.6367899 0.766999183,88.2661632 2.36162048,87.9633241 L2.36162048,87.9633241 L41.7078585,80.4797247 L81.081898,87.94148 C82.6765193,88.2433261 83.9405,86.6089882 83.2454596,85.14146 L83.2454596,85.14146 L43.5229069,1.1378824 C43.1644646,0.379295434 42.4455942,0 41.7267238,0 L41.7267238,0 C41.0088464,-0.00099096544 40.2929547,0.377309604 39.9355054,1.13490366 L39.9355054,1.13490366 Z" id="path-5"></path>
    </defs>
    <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
        <g transform="translate(-113.000000, -190.000000)">
            <g id="arrow" transform="translate(113.000000, 190.000000)">
                <rect fill="#D8D8D8" opacity="0" x="0" y="0" width="88" height="88"></rect>
                <g  transform="translate(2.000000, 0.000000)">
                    <g>
                        <mask id="mask-2" fill="white">
                            <use xlink:href="#path-1"></use>
                        </mask>
                        <g id="Clip-2"></g>
                        <polyline id="Fill-1" fill="#5189F2" mask="url(#mask-2)" points="-1.83344489 89.0261402 41.7048797 70.6879953 41.7038868 -2.9167848"></polyline>
                    </g>
                    <g>
                        <mask id="mask-4" fill="white">
                            <use xlink:href="#path-3"></use>
                        </mask>
                        <g id="Clip-4"></g>
                        <polyline id="Fill-3" fill="#3761F3" mask="url(#mask-4)" points="85.2435022 89.0232608 41.7041847 70.6851158 41.7041847 -2.91767843"></polyline>
                    </g>
                    <g>
                        <mask id="mask-6" fill="white">
                            <use xlink:href="#path-5"></use>
                        </mask>
                        <g id="Clip-6"></g>
                        <polygon id="Fill-5" fill="#2949B4" mask="url(#mask-6)" points="41.7093478 80.7774006 85.2496583 89.030509 41.7043833 70.6844208 -1.83394135 89.0235586"></polygon>
                    </g>
                </g>
            </g>
        </g>
    </g>
</svg>
        `
}

// 扩展的图标
const RotatingIcon = L.DivIcon.extend({
    // constructor
    initialize(iconName) {
        this.iconName = iconName
    },
    createIcon: function (options) {
        const container = document.createElement('div')
        const icon = document.createElement('div')
        icon.style = `
            width: 34px;
            height: 34px;
            border-radius: 50%;
            background:#fff;
            display: flex;
            justify-content: center;
            align-items: center;
            box-shadow: 1px 1px 15px 2px rgba(125, 157, 244, 0.3),
                        -1px -1px 15px 2px rgba(125, 157, 244, 0.3),
                        -1px 1px 15px 2px rgba(125, 157, 244, 0.3),
                        1px -1px 15px 2px rgba(125, 157, 244, 0.3);
        `
        icon.className = 'rambler-moving-marker-icon'
        // icon.style.transition = 'all 0.5s'
        icon.style.position = 'relative'
        icon.style.top = '-17px'
        icon.style.left = '-17px'
        // 图标
        const img = new Image(20, 20)
        img.style = `position: relative; top: -2px`
        img.src = setupIcon(this.iconName)
        icon.appendChild(img)
        this.icon = icon
        container.appendChild(icon)
        return container
    },
    rotate(deg, reverse) {
        this.icon.style.transition = reverse ? 'none' : 'all 0.5s'
        this.icon.style.transform = 'rotate(' + deg + 'deg)'
    }
})

/**
 * 组装base64格式的图片
 * @param {*} name
 * @returns
 */
function setupIcon(name) {
    const svgStr = iconBase64Map[name]
    return `data:image/svg+xml;base64,${btoa(decodeURIComponent(encodeURIComponent(svgStr)))}`
}
